﻿using JV.Com.Business.Log;
using JV.Com.Model;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Data.Xml.Dom;

namespace JV.Com.Business
{
    public static class Service
    {
        public static async Task<IEnumerable<string>> GetSuggestions(string term)
        {
            try
            {
                var results = new List<string>();

                var result = await Downloader.Instance.DownloadStringAsync(RequestUrl.Get(RequestType.GetSuggestions, term));
                var flux = Tools.GetXmlRoot(result);

                foreach (var node in flux.ChildNodes)
                {
                    if (node is XmlElement)
                    {
                        var sug = ((XmlElement)node).GetValueOfCData();
                        results.Add(sug);
                    }
                }

                return results;
            }
            catch
            {
                throw;
            }
        }

        public static async Task<Dictionary<int, List<Game>>> SearchGamesAsync(string term)
        {
            try
            {
                var games = new Dictionary<int, List<Game>>();

                var result = await Downloader.Instance.DownloadStringAsync(RequestUrl.Get(RequestType.SearchGames, term));
                var flux = Tools.GetXmlRoot(result);

                foreach (var systemResult in flux.ChildNodes)
                {
                    if (systemResult is XmlElement)
                    {
                        var systemNode = (XmlElement)systemResult;
                        var idMachine = int.Parse(systemNode.GetValueOfElement("id_machine"));
                        games[idMachine] = new List<Game>();

                        foreach (var gameResult in systemNode.GetElementsByTagName("res_jeux").First().ChildNodes)
                        {
                            if (gameResult is XmlElement)
                            {
                                var gameNode = (XmlElement)gameResult;
                                var game = new Game();
                                game.Id = int.Parse(gameNode.GetValueOfElement("id_jeu"));
                                game.Title = gameNode.GetValueOfElementAndCData("nom_jeu");
                                if(gameNode.ChildNodes.Any(c => c.NodeName == "support"))
                                {
                                    game.Support = gameNode.GetValueOfElementAndCData("support");
                                }
                                games[idMachine].Add(game);
                            }
                        }
                    }
                }

                return games;
            }
            catch
            {
                // TODO ?
                throw;
            }
        }

        public static async Task FillNewsContentAsync(News news)
        {
            try
            {
                var newsXml = await Downloader.Instance.DownloadStringAsync(RequestUrl.Get(RequestType.GetNews, news.Id));
                var flux = Tools.GetXmlRoot(newsXml);

                if (flux is XmlElement)
                {
                    var element = (XmlElement)flux;

                    news.Title = element.GetValueOfElementAndCData("titre");
                    news.Date = DateTime.ParseExact(element.GetValueOfElementAndCData("date"), "dd-MM-yyyy", CultureInfo.InvariantCulture);
                    var time = element.GetValueOfElementAndCData("heure");
                    var hours = int.Parse(time.Split(':')[0]);
                    var minutes = int.Parse(time.Split(':')[1]);
                    news.Hour = new TimeSpan(hours, minutes, 0);
                    news.Content = element.GetConcatCData("texte");
                }
            }
            catch
            {
                throw;
            }
        }

        public static async Task FillGameScreenshotsAsync(Game game)
        {
            var result = await Downloader.Instance.DownloadStringAsync(RequestUrl.Get(RequestType.GetGameScreenshots, game.Id));
            var flux = Tools.GetXmlRoot(result);

            foreach(var node in flux.ChildNodes)
            {
                if(node is XmlElement)
                {
                    var element = node as XmlElement;
                    var id = int.Parse(element.GetValueOfElement("id"));
                    game.SmallScreenshots.Add(id, element.GetValueOfElement("url_vignette"));
                    game.LargeScreenshots.Add(id, element.GetValueOfElement("url_screenshot"));
                }
            }
        }

        public static async Task FillGameDetailsAsync(Game game)
        {
            var result = await Downloader.Instance.DownloadStringAsync(RequestUrl.Get(RequestType.GetGameDetails, game.Id));
            var flux = Tools.GetXmlRoot(result);

            foreach (var node in flux.ChildNodes)
            {
                if (node is XmlElement)
                {
                    var element = node as XmlElement;
                    game.Summary = element.GetValueOfElement("resume");
                    game.ForumUri = element.GetValueOfElementAndCData("url_forum");
                    game.CheatsUri = element.GetValueOfElementAndCData("url_astuces");

                    if (element.NodeName == "articles")
                    {
                        foreach(var articleNode in node.ChildNodes)
                        {
                            if(articleNode is XmlElement)
                            {
                                var articleElement = articleNode as XmlElement;
                                
                                var type = articleElement.GetValueOfElement("type");
                                var article = Article.Create(type);
                                article.Id = int.Parse(articleElement.GetValueOfElementAndCData("id"));
                                article.Title = articleElement.GetValueOfElementAndCData("titre");

                                if (article.Type == ArticleType.Folder)
                                {
                                    var folder = (Folder)article;
                                }
                                else if (article.Type == ArticleType.Preview)
                                {

                                }
                                else if (article.Type == ArticleType.Test)
                                {
                                    var test = (Test)article;
                                    test.Rating = int.Parse(articleElement.GetValueOfElementAndCData("note"));
                                }
                                else throw new NotSupportedException();

                                game.Articles.Add(article);
                            }
                        }
                    }
                }
            }
        }

        public static async Task<Preview> GetGamePreviewAsync(int previewId)
        {
            try
            {
                var preview = new Preview();
                var previewXml = await Downloader.Instance.DownloadStringAsync(RequestUrl.Get(RequestType.GetGamePreview, previewId));
                var flux = Tools.GetXmlRoot(previewXml);

                if (flux is XmlElement)
                {
                    var element = (XmlElement)flux;

                    preview.Id = previewId;
                    preview.Title = element.GetValueOfElementAndCData("titre");
                    preview.Url = element.GetValueOfElementAndCData("url_jv");
                    preview.ImageTopUrl = element.GetValueOfElement("url_chapeau");
                    preview.Date = DateTime.ParseExact(element.GetValueOfElementAndCData("date"), "dd-MM-yyyy", CultureInfo.InvariantCulture);
                    preview.Author = element.GetValueOfElementAndCData("auteur");

                    preview.Machines = new List<int>();
                    foreach (var machineNode in element.ChildNodes.Where(c => c.NodeName == "machine"))
                    {
                        if (machineNode is XmlElement)
                        {
                            var machine = (XmlElement)machineNode;
                            preview.Machines.Add(int.Parse(machine.GetValueOfCData()));
                        }
                    }

                    preview.Content = element.GetConcatCData("texte");
                }

                return preview;
            }
            catch
            {
                throw;
            }
        }
        public static async Task<Test> GetGameTestAsync(int testId)
        {
            try
            {
                var test = new Test();

                var testXml = await Downloader.Instance.DownloadStringAsync(RequestUrl.Get(RequestType.GetGameTest, testId));
                var flux = Tools.GetXmlRoot(testXml);

                if (flux is XmlElement)
                {
                    var element = (XmlElement)flux;

                    test.Id = testId;
                    test.Title = element.GetValueOfElementAndCData("titre");
                    test.Url = element.GetValueOfElementAndCData("url_jv");
                    test.ImageTopUrl = element.GetValueOfElement("url_chapeau");
                    test.Date = DateTime.ParseExact(element.GetValueOfElementAndCData("date"), "dd-MM-yyyy", CultureInfo.InvariantCulture);
                    test.Author = element.GetValueOfElementAndCData("auteur");

                    test.Machines = new List<int>();
                    foreach (var machineNode in element.ChildNodes.Where(c => c.NodeName == "machine"))
                    {
                        if (machineNode is XmlElement)
                        {
                            var machine = (XmlElement)machineNode;
                            test.Machines.Add(int.Parse(machine.GetValueOfCData()));
                        }
                    }

                    test.Content = element.GetConcatCData("texte");
                    test.Rating = int.Parse(element.GetValueOfElementAndCData("note"));
                    test.GlobalReview = element.GetValueOfElementAndCData("texte_generale");
                }

                return test;
            }
            catch
            {
                throw;
            }
        }
        
        public static async Task<Game> GetGameAsync(int gameId)
        {
            try
            {
                var game = new Game();

                var result = await Downloader.Instance.DownloadStringAsync(RequestUrl.Get(RequestType.GetGame, gameId));
                var flux = Tools.GetXmlRoot(result);

                if (flux is XmlElement)
                {
                    var element = (XmlElement)flux;

                    game.Id = gameId;
                    game.Title = element.GetValueOfElementAndCData("titre");
                    game.Machine = int.Parse(element.GetValueOfElementAndCData("id_machine"));
                    game.ReleaseDate = element.GetValueOfElementAndCData("date_sortie");
                    game.Editor = element.GetValueOfElementAndCData("editeur");
                    game.Developer = element.GetValueOfElementAndCData("developpeur");
                    game.Support = element.GetValueOfElementAndCData("support");
                    var multi = element.GetValueOfElementAndCData("multi-joueurs");
                    if(!string.IsNullOrEmpty(multi))
                    {
                        game.Multiplayer = multi == "oui";
                    }
                    game.Version = element.GetValueOfElementAndCData("version");
                    game.Classification = element.GetValueOfElementAndCData("classification");
                    game.SmallImageUrl = element.GetValueOfElement("vignette");
                    game.LargeImageUrl = element.GetValueOfElement("vignette_grande");
                    game.Url = element.GetValueOfElement("url_jv");
                }

                return game;
            }
            catch
            {
                throw;
            }
        }

        public static async Task<FolderPage> GetFolderPageAsync(int folderId, int folderPage)
        {
            try
            {
                var page = new FolderPage();

                if (folderPage == 0) page.NextPage = 1;
                else if (folderPage == 1) page.PrevPage = 0;

                var uri = string.Empty;
                if(folderPage == 0) uri = RequestUrl.Get(RequestType.GetFolder, folderId);
                else uri = RequestUrl.Get(RequestType.GetFolderFrom, folderId, folderPage);

                var result = await Downloader.Instance.DownloadStringAsync(uri);
                var flux = Tools.GetXmlRoot(result);

                if (flux is XmlElement)
                {
                    var element = (XmlElement)flux;

                    page.Title = element.GetValueOfElementAndCData("titre");
                    page.Content = element.GetConcatCData("texte");
                    var next = element.GetValueOfElement("id_suivante");
                    if (!string.IsNullOrEmpty(next)) page.NextPage = int.Parse(next);
                    var prev = element.GetValueOfElement("id_precedente");
                    if (!string.IsNullOrEmpty(prev)) page.PrevPage = int.Parse(prev);
                }

                return page;
            }
            catch
            {
                // TODO ?
                throw;
            }
        }

        public static async Task FillFolderScreenshotAsync(Folder folder, string screenUrl)
        {
            var result = await Downloader.Instance.DownloadStringAsync(RequestUrl.Get(RequestType.GetFolderScreenshots, folder.Id, screenUrl));
            var flux = Tools.GetXmlRoot(result);

            foreach (var node in flux.ChildNodes)
            {
                if (node is XmlElement)
                {
                    var element = node as XmlElement;
                    var id = int.Parse(element.GetValueOfElement("id"));
                    folder.SmallScreenshots.Add(id, element.GetValueOfElement("url_vignette"));
                    folder.LargeScreenshots.Add(id, element.GetValueOfElement("url_screenshot"));
                }
            }
        }

        public static async Task<Folder> GetFolderAsync(int folderId)
        {
            try
            {
                var folder = new Folder();

                var uri = RequestUrl.Get(RequestType.GetFolder, folderId);
                var result = await Downloader.Instance.DownloadStringAsync(uri);
                var flux = Tools.GetXmlRoot(result);

                if (flux is XmlElement)
                {
                    var element = (XmlElement)flux;

                    folder.Id = folderId;
                    folder.Title = element.GetValueOfElementAndCData("titre");
                    folder.Date = DateTime.ParseExact(element.GetValueOfElementAndCData("date"), "dd-MM-yyyy", CultureInfo.InvariantCulture);
                    folder.Author = element.GetValueOfElementAndCData("auteur");
                    folder.SmallImageUrl = element.GetValueOfElement("url_vignette");
                    folder.Url = element.GetValueOfElementAndCData("url_jv");
                    folder.Content = element.GetConcatCData("texte");

                    folder.Machines = new List<int>();
                    foreach (var machineNode in element.ChildNodes.Where(c => c.NodeName == "id_machine"))
                    {
                        if (machineNode is XmlElement)
                        {
                            var machine = (XmlElement)machineNode;
                            folder.Machines.Add(int.Parse(machine.GetValueOfCData()));
                        }
                    }
                }

                return folder;
            }
            catch
            {
                // TODO ?
                throw;
            }
        }

        public static async Task<IEnumerable<News>> GetLatestNewsAsync(int page)
        {
            try
            {
                var news = new List<News>();

                var uri = string.Empty;
                if (page == 0) uri = RequestUrl.Get(RequestType.GetLastNews);
                else uri = RequestUrl.Get(RequestType.GetLastNewsFrom, page);

                var result = await Downloader.Instance.DownloadStringAsync(uri);
                var flux = Tools.GetXmlRoot(result);

                foreach(var node in flux.ChildNodes)
                {
                    if (node is XmlElement)
                    {
                        var element = (XmlElement)node;

                        var n = new News();
                        n.Id = int.Parse(element.GetValueOfElementAndCData("id"));
                        n.Title = element.GetValueOfElementAndCData("titre");
                        n.Summary = element.GetValueOfElementAndCData("resume");
                        n.Date = DateTime.ParseExact(element.GetValueOfElementAndCData("date"), "dd-MM-yyyy", CultureInfo.InvariantCulture);
                        n.SmallImageUrl = element.GetValueOfElement("url_vignette");
                        n.LargeImageUrl = element.GetValueOfElement("vignette_grande");

                        n.Machines = new List<int>();
                        foreach(var machineNode in element.ChildNodes.Where(c => c.NodeName == "id_machine"))
                        {
                            if(machineNode is XmlElement)
                            {
                                var machine = (XmlElement)machineNode;
                                n.Machines.Add(int.Parse(machine.GetValueOfCData()));
                            }
                        }
                        news.Add(n);
                    }
                }

                return news;
            }
            catch
            {
                // TODO ?
                throw;
            }
        }

        public static async Task<IEnumerable<Article>> GetLatestArticlesAsync(ArticleType articleType, int page)
        {
            try
            {
                var articles = new List<Article>();
                var type = string.Empty;
                switch (articleType)
                {
                    case ArticleType.Test: type = "tests"; break;
                    case ArticleType.Preview: type = "apercus"; break;
                    case ArticleType.Folder: type = "dossier"; break;
                    default: throw new NotSupportedException();
                }

                var uri = string.Empty;
                if(page == 0) uri = RequestUrl.Get(RequestType.GetLastArticles, type);
                else uri = RequestUrl.Get(RequestType.GetLastArticlesFrom, type, page);

                var result = await Downloader.Instance.DownloadStringAsync(uri);
                var flux = Tools.GetXmlRoot(result);

                foreach (var node in flux.ChildNodes)
                {
                    if (node is XmlElement)
                    {
                        var element = (XmlElement)node;

                        var article = Article.Create(articleType);
                        article.Type = articleType;
                        article.Id = int.Parse(element.GetValueOfElementAndCData("id"));
                        article.Title = element.GetValueOfElementAndCData("titre");
                        article.Date = DateTime.ParseExact(element.GetValueOfElementAndCData("date"), "dd-MM-yyyy", CultureInfo.InvariantCulture);
                        article.SmallImageUrl = element.GetValueOfElement("url_vignette");

                        article.Machines = new List<int>();
                        foreach (var machineNode in element.ChildNodes.Where(c => c.NodeName == (article.Type == ArticleType.Folder ? "c" : "machine")))
                        {
                            if (machineNode is XmlElement)
                            {
                                var machine = (XmlElement)machineNode;
                                article.Machines.Add(int.Parse(machine.GetValueOfCData()));
                            }
                        }

                        if (article.Type == ArticleType.Folder)
                        {

                        }
                        else if (article.Type == ArticleType.Preview)
                        {
                            var preview = (Preview)article;
                            var rating = element.GetValueOfElementAndCData("note");
                            switch(rating)
                            {
                                case "tres bon": preview.Rating = PreviewRating.VeryGood; break;
                                case "bon": preview.Rating = PreviewRating.Good; break;
                                case "moyen": preview.Rating = PreviewRating.Medium; break;
                                case "mauvais": preview.Rating = PreviewRating.Bad; break;
                                default: throw new NotSupportedException();
                            }
                            //preview.LargeImageUrl = element.GetValueOfElement("vignette_grande");
                            //preview.Editor = element.GetValueOfElementAndCData("editeur");
                            //preview.Developer = element.GetValueOfElementAndCData("developpeur");
                            //preview.ReleaseDate = element.GetValueOfElementAndCData("date_sortie");

                        }
                        else if (article.Type == ArticleType.Test)
                        {
                            var test = (Test)article;
                            test.Rating = int.Parse(element.GetValueOfElementAndCData("note"));
                        }
                        else throw new NotSupportedException();

                        articles.Add(article);
                    }
                }

                return articles;
            }
            catch
            {
                // TODO ?
                throw;
            }
        }
    }
}
